/*******************************************************************************
 * Copyright (c) 2000, 2014 QNX Software Systems and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     QNX Software Systems - Initial API and implementation
 *     Markus Schorn (Wind River Systems)
 *	   IBM Corporation - EFS support
 *******************************************************************************/
package org.eclipse.cdt.core.model;

import java.net.URI;
import java.util.List;

import org.eclipse.cdt.core.CCProjectNature;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.CProjectNature;
import org.eclipse.cdt.core.language.settings.providers.ILanguageSettingsProvidersKeeper;
import org.eclipse.cdt.core.language.settings.providers.LanguageSettingsManager;
import org.eclipse.cdt.core.language.settings.providers.ScannerDiscoveryLegacySupport;
import org.eclipse.cdt.core.resources.IPathEntryStore;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICLanguageSetting;
import org.eclipse.cdt.core.settings.model.ICLanguageSettingEntry;
import org.eclipse.cdt.core.settings.model.ICProjectDescription;
import org.eclipse.cdt.core.settings.model.ICProjectDescriptionListener;
import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager;
import org.eclipse.cdt.core.settings.model.ICSettingEntry;
import org.eclipse.cdt.core.settings.model.WriteAccessException;
import org.eclipse.cdt.internal.core.model.APathEntry;
import org.eclipse.cdt.internal.core.model.BatchOperation;
import org.eclipse.cdt.internal.core.model.CModel;
import org.eclipse.cdt.internal.core.model.CModelManager;
import org.eclipse.cdt.internal.core.model.ContainerEntry;
import org.eclipse.cdt.internal.core.model.IncludeEntry;
import org.eclipse.cdt.internal.core.model.IncludeFileEntry;
import org.eclipse.cdt.internal.core.model.LibraryEntry;
import org.eclipse.cdt.internal.core.model.MacroEntry;
import org.eclipse.cdt.internal.core.model.MacroFileEntry;
import org.eclipse.cdt.internal.core.model.OutputEntry;
import org.eclipse.cdt.internal.core.model.PathEntryManager;
import org.eclipse.cdt.internal.core.model.ProjectEntry;
import org.eclipse.cdt.internal.core.model.SourceEntry;
import org.eclipse.cdt.internal.core.settings.model.CLanguageSettingCache;
import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager;
import org.eclipse.cdt.internal.core.util.MementoTokenizer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.core.runtime.jobs.ISchedulingRule;

/**
 * @noextend This class is not intended to be subclassed by clients.
 * @noinstantiate This class is not intended to be instantiated by clients.
 */
public class CoreModel {
	private static CoreModel cmodel;
	private static final CModelManager manager = CModelManager.getDefault();
	private static final PathEntryManager pathEntryManager = PathEntryManager.getDefault();
	private static final  CProjectDescriptionManager descriptionManager = CProjectDescriptionManager.getInstance();

	public final static String CORE_MODEL_ID = CCorePlugin.PLUGIN_ID + ".coremodel"; //$NON-NLS-1$

	/**
	 * Creates an ICElement for an IPath. Returns null if not found.
	 */
	public ICElement create(IPath path) {
		return manager.create(path);
	}

	/**
	 * Creates a translation from an IPath. Returns null if not found.
	 */
	public ITranslationUnit createTranslationUnitFrom(ICProject cproject, IPath path) {
		return manager.createTranslationUnitFrom(cproject, path);
	}

	/**
	 * Creates a translation from a location URI. Returns null if not found.
	 * @since 5.0
	 */
	public ITranslationUnit createTranslationUnitFrom(ICProject cproject, URI locationURI) {
		return manager.createTranslationUnitFrom(cproject, locationURI);
	}

	/**
	 * Returns the C model element corresponding to the given handle identifier
	 * generated by {@code ICElement.getHandleIdentifier()}, or
	 * {@code null} if unable to create the associated element.
	 *
	 * @param handleIdentifier the given handle identifier
	 * @return the C element corresponding to the handle identifier
	 *
	 * @since 5.0
	 */
	public static ICElement create(String handleIdentifier) {
		if (handleIdentifier == null) {
			return null;
		}
		MementoTokenizer memento = new MementoTokenizer(handleIdentifier);
		return manager.getCModel().getHandleFromMemento(memento);
	}

	/**
	 * Creates an ICElement for an IFile. Returns null if not found.
	 */
	public ICElement create(IFile file) {
		return manager.create(file, null);
	}

	/**
	 * Creates an ICElement for an IFolder. Returns null if not found.
	 */
	public ICContainer create(IFolder folder) {
		return manager.create(folder, null);
	}

	/**
	 * Creates an ICElement for an IProject. Returns null if not found.
	 */
	public ICProject create(IProject project) {
		if (project == null) {
			return null;
		}
		CModel cModel = manager.getCModel();
		return cModel.getCProject(project);
	}

	/**
	 * Creates an ICElement for an IResource. Returns null if not found.
	 */
	public ICElement create(IResource resource) {
		return manager.create(resource, null);
	}

	/**
	 * Returns the C model.
	 *
	 * @param root the given root
	 * @return the C model, or {@code null} if the root is null
	 */
	public static ICModel create(IWorkspaceRoot root) {
		if (root == null) {
			return null;
		}
		return manager.getCModel();
	}

	/**
	 * Returns the default ICModel.
	 */
	public ICModel getCModel() {
		return manager.getCModel();
	}

	/**
	 * Returns true if IFile is a shared library, i.e. libxx.so
	 */
	public boolean isSharedLib(IFile file) {
		ICElement celement = create(file);
		if (celement instanceof IBinary) {
			return ((IBinary)celement).isSharedLib();
		}
		return false;
	}

	/**
	 * Returns true if IFile is a an object(ELF), i.e. *.o
	 */
	public boolean isObject(IFile file) {
		ICElement celement = create(file);
		if (celement instanceof IBinary) {
			return ((IBinary) celement).isObject();
		}
		return false;
	}

	/**
	 * Returns true if IFile is an ELF executable
	 */
	public boolean isExecutable(IFile file) {
		ICElement celement = create(file);
		if (celement instanceof IBinary) {
			return ((IBinary) celement).isExecutable();
		}
		return false;
	}

	/**
	 * Returns true if IFile is an ELF.
	 */
	public boolean isBinary(IFile file) {
		ICElement celement = create(file);
		return celement instanceof IBinary;
	}

	/**
	 * Returns true if IFile is an Achive, *.a
	 */
	public boolean isArchive(IFile file) {
		ICElement celement = create(file);
		return celement instanceof IArchive;
	}

	/**
	 * Returns true if IFile is a possible TranslationUnit.
	 */
	public static boolean isTranslationUnit(IFile file) {
		if (file != null) {
			IProject p = file.getProject();
			if (hasCNature(p) || hasCCNature(p)) {
				return isValidTranslationUnitName(p, file.getFullPath().lastSegment());
			}
		}
		return false;
	}

	/**
	 * Returns an array of the register contentTypes.
	 * @return String[] ids
	 */
	public static String[] getRegistedContentTypeIds() {
		return LanguageManager.getInstance().getRegisteredContentTypeIds();
	}

	/**
	 * Returns true if name is a valid name for a translation unit.
	 */
	public static boolean isValidTranslationUnitName(IProject project, String name) {
		IContentType contentType = CCorePlugin.getContentType(project, name);
		if (contentType != null) {
			String id = contentType.getId();
			return CCorePlugin.CONTENT_TYPE_CHEADER.equals(id)
				|| CCorePlugin.CONTENT_TYPE_CXXHEADER.equals(id)
				|| CCorePlugin.CONTENT_TYPE_CSOURCE.equals(id)
				|| CCorePlugin.CONTENT_TYPE_CXXSOURCE.equals(id)
				|| CCorePlugin.CONTENT_TYPE_ASMSOURCE.equals(id)
				|| LanguageManager.getInstance().isContributedContentType(id);
		}
		return false;
	}

	/**
	 * Returns true if name is a valid name for a translation unit.
	 */
	public static boolean isValidHeaderUnitName(IProject project, String name) {
		IContentType contentType = CCorePlugin.getContentType(project, name);
		if (contentType != null) {
			String id = contentType.getId();
			if (CCorePlugin.CONTENT_TYPE_CHEADER.equals(id) ||
					CCorePlugin.CONTENT_TYPE_CXXHEADER.equals(id)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Returns true if name is a valid name for a translation unit.
	 */
	public static boolean isValidSourceUnitName(IProject project, String name) {
		IContentType contentType = CCorePlugin.getContentType(project, name);
		if (contentType != null) {
			String id = contentType.getId();
			if (CCorePlugin.CONTENT_TYPE_CHEADER.equals(id)
					|| CCorePlugin.CONTENT_TYPE_CXXHEADER.equals(id)) {
				return false;
			}

			return CCorePlugin.CONTENT_TYPE_CSOURCE.equals(id)
				|| CCorePlugin.CONTENT_TYPE_CXXSOURCE.equals(id)
				|| CCorePlugin.CONTENT_TYPE_ASMSOURCE.equals(id)
				|| LanguageManager.getInstance().isContributedContentType(id);
		}
		return false;
	}

	/**
	 * Returns true if name is a valid name for a translation unit.
	 */
	public static boolean isValidCSourceUnitName(IProject project, String name) {
		IContentType contentType = CCorePlugin.getContentType(project, name);
		if (contentType != null) {
			String id = contentType.getId();
			if (CCorePlugin.CONTENT_TYPE_CSOURCE.equals(id)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Returns true if name is a valid name for a translation unit.
	 */
	public static boolean isValidCXXSourceUnitName(IProject project, String name) {
		IContentType contentType = CCorePlugin.getContentType(project, name);
		if (contentType != null) {
			String id = contentType.getId();
			if (CCorePlugin.CONTENT_TYPE_CXXSOURCE.equals(id)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Returns true if name is a valid name for a translation unit.
	 */
	public static boolean isValidASMSourceUnitName(IProject project, String name) {
		IContentType contentType = CCorePlugin.getContentType(project, name);
		if (contentType != null) {
			String id = contentType.getId();
			if (CCorePlugin.CONTENT_TYPE_ASMSOURCE.equals(id)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Returns true if name is a valid name for a translation unit.
	 */
	public static boolean isValidCXXHeaderUnitName(IProject project, String name) {
		IContentType contentType = CCorePlugin.getContentType(project, name);
		if (contentType != null) {
			String id = contentType.getId();
			if (CCorePlugin.CONTENT_TYPE_CXXHEADER.equals(id)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Returns true if name is a valid name for a translation unit.
	 */
	public static boolean isValidCHeaderUnitName(IProject project, String name) {
		IContentType contentType = CCorePlugin.getContentType(project, name);
		if (contentType != null) {
			String id = contentType.getId();
			if (CCorePlugin.CONTENT_TYPE_CHEADER.equals(id)) {
				return true;
			}
		}
		return false;
	}

	/**
	 *  Return the registered content type id, for example:
	 *  <ul>
	 *  <li>CONTENT_TYPE_CHEADER
	 *  <li>CONTENT_TYPE_CXXHEADER
	 *  <li>CONTENT_TYPE_CSOURCE
	 *  <li>CONTENT_TYPE_CXXSOURCE
	 *  <li>CONTENT_TYPE_ASMSOURCE
	 *  </ul>
	 *  or null is return if no id match the list
	 * @return the know id or null
	 */
	public static String getRegistedContentTypeId(IProject project, String name) {
		IContentType contentType = CCorePlugin.getContentType(project, name);
		if (contentType != null && LanguageManager.getInstance().getLanguage(contentType) != null) {
			return contentType.getId();
		}
		return null;
	}

	/**
	 * Returns true if project has C nature.
	 */
	public static boolean hasCNature(IProject project) {
		try {
			return project.isOpen() && project.hasNature(CProjectNature.C_NATURE_ID);
		} catch (CoreException e) {
		}
		return false;
	}

	/**
	 * Returns true if project has C++ nature.
	 */
	public static boolean hasCCNature(IProject project) {
		try {
			return project.isOpen() && project.hasNature(CCProjectNature.CC_NATURE_ID);
		} catch (CoreException e) {
		}
		return false;
	}

	/**
	 * Creates and returns a new non-exported entry of kind {@code CDT_PROJECT}
	 * for the project identified by the given absolute path.
	 * <p>
	 * A project entry is used to denote a prerequisite project. The
	 * exported IPathEntry[] entries of the project will be contributed.
	 * <p>
	 * The prerequisite project is referred to using an absolute path relative
	 * to the workspace root.
	 * <p>
	 * The resulting entry is not exported to dependent projects. This method
	 * is equivalent to {@code newProjectEntry(path, false)}.
	 * <p>
	 *
	 * @param projectPath
	 *            the workspace-relative path of the project
	 * @return a new project entry
	 *
	 * @see CoreModel#newProjectEntry(IPath, boolean)
	 */
	public static IProjectEntry newProjectEntry(IPath projectPath) {
		return newProjectEntry(projectPath, false);
	}

	/**
	 * Creates and returns a new entry of kind {@code CDT_PROJECT} for
	 * the project identified by the given workspace-relative path.
	 * <p>
	 * A project entry is used to denote a prerequisite project. All the
	 * IPathEntries of the project will be contributed as a whole. The
	 * prerequisite project is referred to using an absolute path relative to
	 * the workspace root.
	 * <p>
	 *
	 * @param projectPath
	 *            the absolute workspace-relative path of the prerequisite project
	 * @param isExported
	 *            indicates whether this entry is contributed to dependent
	 *            projects
	 * @return a new project entry
	 */
	public static IProjectEntry newProjectEntry(IPath projectPath, boolean isExported) {
		return new ProjectEntry(projectPath, isExported);
	}

	/**
	 * Creates and returns a new entry of kind {@code CDT_CONTAINER} for
	 * the given path. The path of the container will be used during resolution
	 * so as to map this container entry to a set of other entries the
	 * container is acting for.
	 * <p>
	 * The resulting entry is not exported to dependent projects. This method
	 * is equivalent to {@code newContainerEntry(path, false)}.
	 * <p>
	 *
	 * @param id the id of the container
	 * @return a new container entry
	 *
	 */
	public static IContainerEntry newContainerEntry(IPath id) {
		return newContainerEntry(id, false);
	}

	/**
	 * Creates and returns a new entry of kind {@code CDT_CONTAINER} for
	 * the given path. The path of the container will be used during resolution
	 * so as to map this container entry to a set of other entries the
	 * container is acting for.
	 * <p>
	 * The resulting entry is not exported to dependent projects. This method
	 * is equivalent to {@code newContainerEntry(path,false)}.
	 * <p>
	 */
	public static IContainerEntry newContainerEntry(IPath id, boolean isExported) {
		return new ContainerEntry(id, isExported);
	}

	/**
	 * Creates and returns a new entry of kind {@code CDT_LIBRARY}
	 * for the archive or folder identified by the given absolute path.
	 *
	 * @param resourcePath
	 *            the affected project-relative resource path
	 * @param baseRef
	 *            the base reference path to find the library
	 * @param libraryPath
	 *            the library name.
	 * @return a new library entry
	 *
	 */
	public static ILibraryEntry newLibraryRefEntry(IPath resourcePath, IPath baseRef, IPath libraryPath) {
		return new LibraryEntry(resourcePath, null, baseRef, libraryPath, null, null, null, false);
	}

	/**
	 * Creates and returns a new entry of kind {@code CDT_LIBRARY}
	 * for the archive or folder identified by the given absolute path.
	 *
	 * Note that this operation does not attempt to validate or access the
	 * resources at the given paths.
	 * <p>
	 *
	 * @param resourcePath
	 *            the affected project-relative resource path
	 * @param basePath
	 *            the base path of the library
	 * @param libraryPath
	 *            the path of the library
	 * @param sourceAttachmentPath
	 *            the project-relative path of the corresponding source archive or
	 *            folder, or {@code null} if none.
	 * @param sourceAttachmentRootPath
	 *            the location of the root within the source archive or folder
	 *            or {@code null}.
	 * @param sourceAttachmentPrefixMapping
	 *            prefix mapping or {@code null}.
	 * @param isExported
	 *           whether the entry is exported
	 * @return a new library entry
	 *
	 */
	public static ILibraryEntry newLibraryEntry(IPath resourcePath, IPath basePath, IPath libraryPath, IPath sourceAttachmentPath, IPath sourceAttachmentRootPath,
			IPath sourceAttachmentPrefixMapping, boolean isExported) {
		return new LibraryEntry(resourcePath, basePath, null, libraryPath, sourceAttachmentPath, sourceAttachmentRootPath, sourceAttachmentPrefixMapping, isExported);
	}

	/**
	 * Creates and returns a new entry of kind {@code CDT_OUTPUT} for
	 * the project's output folder
	 * <p>
	 *
	 * @param outputPath
	 *            the project-relative path of a folder
	 * @return a new source entry with not exclusion patterns
	 *
	 */
	public static IOutputEntry newOutputEntry(IPath outputPath) {
		return newOutputEntry(outputPath, APathEntry.NO_EXCLUSION_PATTERNS);
	}

	/**
	 * Creates and returns a new entry of kind {@code CDT_OUPUT} for
	 * the project
	 *
	 * @param outputPath
	 *            the project-relative path of a folder
	 * @param exclusionPatterns
	 *            the possibly empty list of exclusion patterns represented as
	 *            relative paths
	 * @return a new source entry with the given exclusion patterns
	 */
	public static IOutputEntry newOutputEntry(IPath outputPath, IPath[] exclusionPatterns) {
		return new OutputEntry(outputPath, exclusionPatterns, false);
	}

	/**
	 * Creates and returns a new entry of kind {@code CDT_SOURCE} for
	 * the project's source folder identified by the given absolute
	 * workspace-relative path.
	 * <p>
	 * The source folder is referred to using an absolute path relative to the
	 * workspace root, e.g. {@code /Project/src}. A project's source
	 * folders are located with that project. That is, a source entry
	 * specifying the path {@code /P1/src} is only usable for project
	 * {@code P1}.
	 * <p>
	 * Note that all sources/binaries inside a project are contributed as a
	 * whole through a project entry (see {@code newProjectEntry}).
	 * Particular source entries cannot be selectively exported.
	 *
	 * @param sourcePath the project-relative path of a source folder
	 * @return a new source entry with not exclusion patterns
	 *
	 */
	public static ISourceEntry newSourceEntry(IPath sourcePath) {
		return newSourceEntry(sourcePath, APathEntry.NO_EXCLUSION_PATTERNS);
	}

	/**
	 * Creates and returns a new entry of kind {@code CDT_SOURCE} for
	 * the project's source folder identified by the given absolute
	 * workspace-relative path but excluding all source files with paths
	 * matching any of the given patterns. This specifies that all package
	 * fragments within the root will have children of type {@code ICompilationUnit}.
	 * <p>
	 * The source folder is referred to using an absolute path relative to the
	 * workspace root, e.g. {@code /Project/src}. A project's source
	 * folders are located with that project. That is, a source entry
	 * specifying the path {@code /P1/src} is only usable for project
	 * {@code P1}.
	 *
	 * @param sourcePath
	 *            the absolute project-relative path of a source folder
	 * @param exclusionPatterns
	 *            the possibly empty list of exclusion patterns represented as
	 *            relative paths
	 * @return a new source entry with the given exclusion patterns
	 */
	public static ISourceEntry newSourceEntry(IPath sourcePath, IPath[] exclusionPatterns) {
		return new SourceEntry(sourcePath, exclusionPatterns);
	}

	/**
	 * Creates and returns a new entry of kind {@code CDT_INCLUDE}
	 *
	 * @param resourcePath
	 *            the affected project-relative resource path
	 * @param basePath
	 *            the base path of the includePath
	 * @param includePath
	 *            the absolute path of the include
	 * @return IIncludeEntry
	 */
	public static IIncludeEntry newIncludeEntry(IPath resourcePath, IPath basePath, IPath includePath) {
		return newIncludeEntry(resourcePath, basePath, includePath, true);
	}

	/**
	 * * Creates and returns a new entry of kind {@code CDT_INCLUDE}
	 *
	 * @param resourcePath
	 *            the affected project-relative resource path
	 * @param basePath
	 *            the base path of the includePath
	 * @param includePath
	 *            the absolute path of the include
	 * @param isSystemInclude
	 *            whether this include path should be consider a system include path
	 * @return IIncludeEntry
	 */
	public static IIncludeEntry newIncludeEntry(IPath resourcePath, IPath basePath, IPath includePath, boolean isSystemInclude) {
		return newIncludeEntry(resourcePath, basePath, includePath, isSystemInclude, APathEntry.NO_EXCLUSION_PATTERNS);
	}

	/**
	 * Creates and returns a new entry of kind {@code CDT_INCLUDE}
	 *
	 * @param resourcePath
	 *            the affected project-relative resource path
	 * @param basePath
	 *            the base path of the includePath
	 * @param includePath
	 *            the absolute path of the include
	 * @param isSystemInclude
	 *            whether this include path should be consider the system
	 *            include path
	 * @param exclusionPatterns
	 *            exclusion patterns in the resource if a container
	 * @return IIincludeEntry
	 */
	public static IIncludeEntry newIncludeEntry(IPath resourcePath, IPath basePath, IPath includePath, boolean isSystemInclude, IPath[] exclusionPatterns) {
		return newIncludeEntry(resourcePath, basePath, includePath, isSystemInclude, exclusionPatterns, false);
	}

	/**
	 * Creates and returns a new entry of kind {@code CDT_INCLUDE}
	 *
	 * @param resourcePath
	 *            the affected project-relative resource path
	 * @param basePath
	 *            the base path of the include
	 * @param includePath
	 *            the path of the include
	 * @param isSystemInclude
	 *            whether this include path should be consider the system
	 *            include path
	 * @param exclusionPatterns
	 *            exclusion patterns in the resource if a container
	 * @param isExported
	 *            if the entry ix exported to reference projects
	 * @return IIincludeEntry
	 */
	public static IIncludeEntry newIncludeEntry(IPath resourcePath, IPath basePath, IPath includePath, boolean isSystemInclude,
			 IPath[] exclusionPatterns, boolean isExported) {
		return new IncludeEntry(resourcePath, basePath, null, includePath, isSystemInclude, exclusionPatterns, isExported);
	}

	/**
	 * Creates and returns a new entry of kind {@code CDT_INCLUDE}
	 *
	 * @param resourcePath
	 *            the affected project-relative resource path
	 * @param baseRef
	 *            the base reference path of the include
	 * @param includePath
	 *            the path of the include
	 * @return IIincludeEntry
	 */
	public static IIncludeEntry newIncludeRefEntry(IPath resourcePath, IPath baseRef, IPath includePath) {
		return new IncludeEntry(resourcePath, null, baseRef, includePath, true, null, false);
	}

	/**
	 * Creates a new entry of kind {@code CDT_INCLUDE_FILE}
	 */
	public static IIncludeFileEntry newIncludeFileEntry(IPath resourcePath, IPath includeFile) {
		return newIncludeFileEntry(resourcePath, null, null, includeFile, null, false);
	}

	/**
	 * Creates and returns a new entry of kind {@code CDT_INCLUDE_FILE}
	 *
	 * @param resourcePath
	 *            the affected project-relative resource path
	 * @param basePath
	 *            the base path of the include
	 * @param includeFilePath
	 *            the path of the include
	 * @param exclusionPatterns
	 *            exclusion patterns in the resource if a container
	 * @param isExported
	 *            if the entry ix exported to reference projects
	 * @return IIincludeEntry
	 */
	public static IIncludeFileEntry newIncludeFileEntry(IPath resourcePath, IPath baseRef, IPath basePath, IPath includeFilePath,
			 IPath[] exclusionPatterns, boolean isExported) {
		return new IncludeFileEntry(resourcePath, basePath, baseRef, includeFilePath, exclusionPatterns, isExported);
	}

	/**
	 * Creates and returns an entry kind {@code CDT_MACRO}
	 *
	 * @param resourcePath
	 *            the affected project-relative resource path
	 * @param macroName
	 *            the name of the macro
	 * @param macroValue
	 *            the value of the macro
	 * @return IMacroEntry
	 */
	public static IMacroEntry newMacroEntry(IPath resourcePath, String macroName, String macroValue) {
		return newMacroEntry(resourcePath, macroName, macroValue, APathEntry.NO_EXCLUSION_PATTERNS);
	}

	/**
	 * Creates and returns an entry kind {@code CDT_MACRO}
	 *
	 * @param resourcePath
	 *            the affected project-relative resource path
	 * @param macroName
	 *            the name of the macro
	 * @param macroValue
	 *            the value of the macro
	 * @param exclusionPatterns
	 *            exclusion patterns in the resource if a container
	 */
	public static IMacroEntry newMacroEntry(IPath resourcePath, String macroName, String macroValue, IPath[] exclusionPatterns) {
		return newMacroEntry(resourcePath, macroName, macroValue, exclusionPatterns, false);
	}

	/**
	 * Creates and returns an entry kind {@code CDT_MACRO}
	 *
	 * @param resourcePath
	 *            the affected workspace-relative resource path
	 * @param macroName
	 *            the name of the macro
	 * @param macroValue
	 *            the value of the macro
	 * @param exclusionPatterns
	 *            exclusion patterns in the resource if a container
	 */
	public static IMacroEntry newMacroEntry(IPath resourcePath, String macroName, String macroValue, IPath[] exclusionPatterns, boolean isExported) {
		return new MacroEntry(resourcePath, null, macroName, macroValue, exclusionPatterns, isExported);
	}

	/**
	 * Creates and returns an entry kind {@code CDT_MACRO}
	 *
	 * @param resourcePath
	 *            the affected workspace-relative resource path
	 * @param baseRef
	 *        the base reference path
	 * @param macroName
	 *            the name of the macro
	 */
	public static IMacroEntry newMacroRefEntry(IPath resourcePath, IPath baseRef, String macroName) {
		return new MacroEntry(resourcePath, baseRef, macroName, null, APathEntry.NO_EXCLUSION_PATTERNS, false);
	}

	/**
	 * Creates an entry kind {@code CDT_MACRO_FILE}
	 */
	public static IMacroFileEntry newMacroFileEntry(IPath resourcePath, IPath macroFile) {
		return newMacroFileEntry(resourcePath, null, null, macroFile, null, false);
	}

	/**
	 * Creates and returns an entry kind {@code CDT_MACRO_FILE}
	 *
	 * @param resourcePath
	 *            the affected workspace-relative resource path
	 * @param basePath
	 *            the base path
	 * @param macroFilePath
	 *            the file path where the macros are define
	 * @param exclusionPatterns
	 *            exclusion patterns in the resource if a container
	 */
	public static IMacroFileEntry newMacroFileEntry(IPath resourcePath, IPath basePath, IPath baseRef, IPath macroFilePath, IPath[] exclusionPatterns, boolean isExported) {
		return new MacroFileEntry(resourcePath, basePath, baseRef, macroFilePath, exclusionPatterns, isExported);
	}


	/**
	 * Answers the project specific value for a given container. In case this
	 * container path could not be resolved, then will answer {@code null}.
	 * Both the container path and the project context are supposed to be
	 * non-null.
	 * <p>
	 * The containerPath is a formed by a first ID segment followed with extra
	 * segments, which can be used as additional hints for resolution. If no
	 * container was ever recorded for this container path onto this project
	 * (using {@code setPathEntryContainer}, then a {@code PathEntryContainerInitializer}
	 * will be activated if any was registered for this container ID onto the
	 * extension point "org.eclipse.cdt.core.PathEntryContainerInitializer".
	 * <p>
	 * PathEntry container values are persisted locally to the workspace, but
	 * are not preserved from a session to another. It is thus highly
	 * recommended to register a {@code PathEntryContainerInitializer}
	 * for each referenced container (through the extension point
	 * "org.eclipse.cdt.core.PathEntryContainerInitializer").
	 * <p>
	 *
	 * @param containerPath
	 *            the name of the container, which needs to be resolved
	 * @param project
	 *            a specific project in which the container is being resolved
	 * @return the corresponding container or {@code null} if unable to
	 *         find one.
	 *
	 * @exception CModelException
	 *                if an exception occurred while resolving the container,
	 *                or if the resolved container contains illegal entries
	 *                (contains CDT_CONTAINER entries or null entries).
	 *
	 * @see PathEntryContainerInitializer
	 * @see IPathEntryContainer
	 * @see #setPathEntryContainer(ICProject[], IPathEntryContainer, IProgressMonitor)
	 */
	public static IPathEntryContainer getPathEntryContainer(IPath containerPath, ICProject project) throws CModelException {
		return pathEntryManager.getPathEntryContainer(containerPath, project);
	}

	/**
	 * Bind a container reference path to some actual containers ({@code IPathEntryContainer}).
	 * This API must be invoked whenever changes in container need to be
	 * reflected onto the CModel.
	 * <p>
	 * In reaction to changing container values, the CModel will be updated to
	 * reflect the new state of the updated container.
	 * <p>
	 * This functionality cannot be used while the resource tree is locked.
	 * <p>
	 * PathEntry container values are persisted locally to the workspace, but
	 * are not preserved from a session to another. It is thus highly
	 * recommended to register a {@code PathEntryContainerInitializer}
	 * for each referenced container (through the extension point
	 * "org.eclipse.cdt.core.PathEntryContainerInitializer").
	 * <p>
	 * Note: setting a container to {@code null} will cause it to be
	 * lazily resolved again whenever its value is required. In particular,
	 * this will cause a registered initializer to be invoked again.
	 * <p>
	 *
	 * @param affectedProjects -
	 *            the set of projects for which this container is being bound
	 * @param container -
	 *            the container for the affected projects
	 * @param monitor
	 *            a monitor to report progress
	 * @throws CModelException
	 * @see PathEntryContainerInitializer
	 * @see #getPathEntryContainer(IPath, ICProject)
	 * @see IPathEntryContainer
	 */
	public static void setPathEntryContainer(ICProject[] affectedProjects, IPathEntryContainer container, IProgressMonitor monitor)
			throws CModelException {
		pathEntryManager.setPathEntryContainer(affectedProjects, container, monitor);
	}

	/**
	 * Helper method use by a path entry container implementing {@code IPathEntryContainerExtension}
	 * It notify the model of changes.
	 * Note: the paths in the {@code PathEntryContainerChanged[]} array must be on
	 * source that the container was set too.  If not the changes will be silently ignore.
	 *
	 * @param container
	 * @param changes array of changes.
	 * @param monitor progress monitor
	 */
	public static void pathEntryContainerUpdates(IPathEntryContainerExtension container, PathEntryContainerChanged[] changes, IProgressMonitor monitor) {
		pathEntryManager.pathEntryContainerUpdates(container, changes, monitor);
	}

	/**
	 * Sets the pathentries of this project using a list of entries.
	 * <p>
	 * Setting the pathentries to {@code null} specifies a default
	 * classpath (the project root). Setting the pathentry to an empty array
	 * specifies an empty pathentry.
	 * <p>
	 *
	 * @param newEntries
	 *            a list of entries
	 * @param monitor
	 *            the given progress monitor
	 * @exception CModelException
	 *                if the entries could not be set. Reasons include:
	 */
	public static void setRawPathEntries(ICProject cproject, IPathEntry[] newEntries, IProgressMonitor monitor) throws CModelException {
		pathEntryManager.setRawPathEntries(cproject, newEntries, monitor);
	}

	/**
	 * Returns the raw pathentries for the project. This corresponds to the
	 * exact set of entries which were assigned using {@code setRawPathEntries}
	 * <p>
	 *
	 * @return the raw entires for the project
	 * @exception CModelException
	 *                if this element does not exist or if an exception occurs
	 *                while accessing its corresponding resource
	 * @see IPathEntry
	 */
	public static IPathEntry[] getRawPathEntries(ICProject cproject) throws CModelException {
		return pathEntryManager.getRawPathEntries(cproject);
	}

	/**
	 * This method returns the resolved pathentries for the project All
	 * pathEntry.CDT_CONTAINER entries in the project's will be replaced by the
	 * entries they resolve to.
	 * <p>
	 * The resulting resolved entries are accurate for the given point in time.
	 * If the project's raw entries are later modified they can become out of
	 * date. Because of this, hanging on resolved pathentries is not
	 * recommended.
	 *
	 * @return the resolved entries for the project
	 * @exception CModelException
	 * @see IPathEntry
	 */
	public static IPathEntry[] getResolvedPathEntries(ICProject cproject) throws CModelException {
		return pathEntryManager.getResolvedPathEntries(cproject);
	}

	/**
	 * This method returns the include entries associated with a translation unit
	 * if the path does not refer to a valid translation unit an empty array is return.
	 * <p>
	 * The resulting resolved entries are accurate for the given point in time.
	 * If the project's raw entries are later modified they can become out of
	 * date. Because of this, hanging on resolved pathentries is not
	 * recommended.
	 *
	 * @return the include entries for the translation unit
	 * @exception CModelException
	 * @see IPathEntry
	 */
	public static IIncludeEntry[] getIncludeEntries(IPath path) throws CModelException {
		return pathEntryManager.getIncludeEntries(path);
	}

	/**
	 * This method returns the include file entries associated with a translation unit
	 * if the path does not refer to a valid translation unit an empty array is return.
	 * <p>
	 * The resulting resolved entries are accurate for the given point in time.
	 * If the project's raw entries are later modified they can become out of
	 * date. Because of this, hanging on resolved pathentries is not
	 * recommended.
	 *
	 * @return the include file entries for the translation unit
	 * @exception CModelException
	 * @see IPathEntry
	 */
	public static IIncludeFileEntry[] getIncludeFileEntries(IPath path) throws CModelException {
		return pathEntryManager.getIncludeFileEntries(path);
	}

	/**
	 * This method returns the macro entries associated with a translation unit
	 * if the path does not refer to a valid translation unit an empty array is return.
	 * <p>
	 * The resulting resolved entries are accurate for the given point in time.
	 * If the project's raw entries are later modified they can become out of
	 * date. Because of this, hanging on resolved pathentries is not
	 * recommended.
	 *
	 * @return the resolved entries for the project
	 * @exception CModelException
	 * @see IPathEntry
	 */
	public static IMacroEntry[] getMacroEntries(IPath path) throws CModelException {
		return pathEntryManager.getMacroEntries(path);
	}

	/**
	 * This method returns the macro file entries associated with a translation unit
	 * if the path does not refer to a valid translation unit an empty array is return.
	 * <p>
	 * The resulting resolved entries are accurate for the given point in time.
	 * If the project's raw entries are later modified they can become out of
	 * date. Because of this, hanging on resolved pathentries is not
	 * recommended.
	 *
	 * @return the macro file entries for the translation unit
	 * @exception CModelException
	 * @see IPathEntry
	 */
	public static IMacroFileEntry[] getMacroFileEntries(IPath path) throws CModelException {
		return pathEntryManager.getMacroFileEntries(path);
	}

	/**
	 * Helper method finding the pathentry container initializer registered for
	 * a given container ID or {@code null} if none was found while
	 * iterating over the contributions to extension point to the extension
	 * point "org.eclipse.cdt.core.PathEntryContainerInitializer".
	 * <p>
	 * A containerID is the first segment of any container path, used to
	 * identify the registered container initializer.
	 * <p>
	 *
	 * @param containerID -
	 *            a containerID identifying a registered initializer
	 * @return ClasspathContainerInitializer - the registered classpath
	 *         container initializer or {@code null} if none was found.
	 */
	public static PathEntryContainerInitializer getPathEntryContainerInitializer(String containerID) {
		return pathEntryManager.getPathEntryContainerInitializer(containerID);
	}

	/**
	 * Returns the IPathEntryStore of the project.
	 * @throws CoreException
	 */
	public static IPathEntryStore getPathEntryStore(IProject project) throws CoreException {
		return pathEntryManager.getPathEntryStore(project, true);
	}

	/**
	 * Set in the map the store, but not persisted.
	 *
	 * @param project
	 * @param store
	 */
	public static void setPathEntryStore(IProject project, IPathEntryStore store) {
		pathEntryManager.setPathEntryStore(project, store);
	}

	/**
	 * Validate a given path entries for a project, using the following rules:
	 * <ul>
	 *   <li> Entries cannot collide with each other; that is, all entry paths must be unique.
	 *   <li> The output entry location path can be empty, if not they must be located inside
	 *        the project.
	 *   <li> Source entry location can be null, if not they must be located inside the project,
	 *   <li> A project entry cannot refer to itself directly (that is, a project cannot
	 *        prerequisite itself).
     *   <li> Source entries or output locations cannot coincide or be nested in each other, except
     *        for the following scenarios listed below:
	 *      <ul>
	 *        <li> A source folder can coincide with its own output location, in which case this
	 *             output can then contain library archives. However, a specific output location
	 *             cannot coincide with any library or a distinct source folder than the one
	 *             referring to it.</li>
	 *        <li> A source/library folder can be nested in any source folder as long as
	 *             the nested folder is excluded from the enclosing one. </li>
	 * 		  <li> An output location can be nested in a source folder, if the source folder
	 *             coincides with the project itself, or if the output location is excluded from
	 *             the source folder. </li>
	 *      </ul>
	 * </ul>
	 *
	 *  Note that the entries are not validated automatically. Only bound variables or containers
	 *  are considered in the checking process (this allows to perform a consistency check on
	 *  an entry which has references to yet non existing projects, folders, ...).
	 *  <p>
	 *  This validation is intended to anticipate issues prior to assigning it to a project.
	 *  In particular, it will automatically be performed during the setting operation
	 *  (if validation fails, the classpath setting will not complete) and during
	 *  {@link #getResolvedPathEntries}.
	 *
	 * @param cProject the given C project
	 * @return a status object with code {@code IStatus.OK} if
	 *		the entries location are compatible, otherwise a status
	 *		object indicating what is wrong with them
	 */
	public static ICModelStatus validatePathEntries(ICProject cProject, IPathEntry[] entries) {
		return pathEntryManager.validatePathEntry(cProject, entries);
	}

	/**
	 * Returns a C model status describing the problem related to this entry if any,
	 * a status object with code {@code IStatus.OK} if the entry is fine (that is, if the
	 * given entry denotes a valid element).
	 *
	 * @param cProject the given C project
	 * @param entry the given entry
	 * @param checkSourceAttachment a flag to determine if source attachment should be checked
	 * @param recurseInContainers flag indicating whether validation should be applied to container
	 *     entries recursively
	 * @return a c model status describing the problem related to this entry if any, a status object
	 *     with code {@code IStatus.OK} if the entry is fine
	 */
	public static ICModelStatus validatePathEntry(ICProject cProject, IPathEntry entry, boolean checkSourceAttachment, boolean recurseInContainers){
		return pathEntryManager.validatePathEntry(cProject, entry, checkSourceAttachment, recurseInContainers);
	}

	/**
	 * Returns the singleton.
	 */
	public static CoreModel getDefault() {
		if (cmodel == null) {
			cmodel = new CoreModel();
		}
		return cmodel;
	}

	public void addElementChangedListener(IElementChangedListener listener) {
		manager.addElementChangedListener(listener);
	}

	/**
	 * Removes the given element changed listener. Has no affect if an
	 * identical listener is not registered.
	 *
	 * @param listener
	 *            the listener
	 */
	public void removeElementChangedListener(IElementChangedListener listener) {
		manager.removeElementChangedListener(listener);
	}

	/**
	 * @see Plugin#startup
	 */
	public void startup() {
		manager.startup();
	}

	public void shutdown() {
		manager.shutdown();
	}

	private CoreModel() {
	}

	/**
	 * Runs the given action as an atomic C model operation.
	 * <p>
	 * After running a method that modifies C elements,
	 * registered listeners receive after-the-fact notification of
	 * what just transpired, in the form of a element changed event.
	 * This method allows clients to call a number of
	 * methods that modify C elements and only have element
	 * changed event notifications reported at the end of the entire
	 * batch.
	 * <p>
	 * If this method is called outside the dynamic scope of another such
	 * call, this method runs the action and then reports a single
	 * element changed event describing the net effect of all changes
	 * done to C elements by the action.
	 * <p>
	 * If this method is called in the dynamic scope of another such
	 * call, this method simply runs the action.
	 * </p>
	 *
	 * @param action the action to perform
	 * @param monitor a progress monitor, or {@code null} if progress
	 *     reporting and cancellation are not desired
	 * @exception CoreException if the operation failed.
	 * @since 2.1
	 */
	public static void run(IWorkspaceRunnable action, IProgressMonitor monitor) throws CoreException {
		run(action, ResourcesPlugin.getWorkspace().getRoot(), monitor);
	}
	/**
	 * Runs the given action as an atomic C model operation.
	 * <p>
	 * After running a method that modifies C elements,
	 * registered listeners receive after-the-fact notification of
	 * what just transpired, in the form of a element changed event.
	 * This method allows clients to call a number of
	 * methods that modify C elements and only have element
	 * changed event notifications reported at the end of the entire
	 * batch.
	 * <p>
	 * If this method is called outside the dynamic scope of another such
	 * call, this method runs the action and then reports a single
	 * element changed event describing the net effect of all changes
	 * done to C elements by the action.
	 * <p>
	 * If this method is called in the dynamic scope of another such
	 * call, this method simply runs the action.
	 * <p>
 	 * The supplied scheduling rule is used to determine whether this operation can be
	 * run simultaneously with workspace changes in other threads. See
	 * {@link IWorkspace#run} for more details.
	 *
	 * @param action the action to perform
	 * @param rule the scheduling rule to use when running this operation, or
	 *     {@code null} if there are no scheduling restrictions for this operation.
	 * @param monitor a progress monitor, or {@code null} if progress
	 *     reporting and cancellation are not desired
	 * @exception CoreException if the operation failed.
	 * @since 3.0
	 */
	public static void run(IWorkspaceRunnable action, ISchedulingRule rule, IProgressMonitor monitor) throws CoreException {
		IWorkspace workspace = ResourcesPlugin.getWorkspace();
		if (workspace.isTreeLocked()) {
			new BatchOperation(action).run(monitor);
		} else {
			// Use IWorkspace.run(...) to ensure that a build will be done in autobuild mode.
			workspace.run(new BatchOperation(action), rule, IWorkspace.AVOID_UPDATE, monitor);
		}
	}

	/**
	 * The method returns whether scanner information for a resource is empty or not.
	 * If {@code null} is supplied the method returns {@code true}.
	 *
	 * @param resource
	 * @since 3.0
	 */
	public static boolean isScannerInformationEmpty(IResource resource) {
		if (resource == null) {
			return true;
		}
		IProject project = resource.getProject();
		CProjectDescriptionManager mngr = CProjectDescriptionManager.getInstance();
		ICProjectDescription des = mngr.getProjectDescription(project, false);
		if (des != null){
			ICConfigurationDescription indexCfg = des.getDefaultSettingConfiguration();
			if (indexCfg != null){
				if (!mngr.isNewStyleCfg(indexCfg)) {
					return oldIsScannerInformationEmpty(resource);
				}

				if (ScannerDiscoveryLegacySupport.isLanguageSettingsProvidersFunctionalityEnabled(project) &&
						indexCfg instanceof ILanguageSettingsProvidersKeeper) {
					List<String> languageIds = LanguageSettingsManager.getLanguages(resource, indexCfg);
					for (String langId : languageIds) {
						List<ICLanguageSettingEntry> entries = LanguageSettingsManager.getSettingEntriesByKind(indexCfg, resource, langId,
								ICSettingEntry.INCLUDE_PATH | ICSettingEntry.MACRO | ICSettingEntry.INCLUDE_FILE | ICSettingEntry.MACRO_FILE);
						if (!(entries == null || entries.isEmpty())) {
							return false;
						}
					}
					return true;
				} else {
					ICLanguageSetting lSetting = indexCfg.getLanguageSettingForFile(resource.getProjectRelativePath(), false);
					if (lSetting != null && lSetting instanceof CLanguageSettingCache){
						if (!((CLanguageSettingCache)lSetting).containsDiscoveredScannerInfo())
							lSetting = null;
					}
					if (lSetting != null){
						ICLanguageSettingEntry[] entries = lSetting.getSettingEntries(ICSettingEntry.INCLUDE_PATH);
						if (entries.length != 0)
							return false;

						entries = lSetting.getSettingEntries(ICSettingEntry.MACRO);
						if (entries.length != 0)
							return false;

						entries = lSetting.getSettingEntries(ICSettingEntry.INCLUDE_FILE);
						if (entries.length != 0)
							return false;

						entries = lSetting.getSettingEntries(ICSettingEntry.MACRO_FILE);
						if (entries.length != 0)
							return false;
					}
				}
			}
		}
		return true;
	}

	private static boolean oldIsScannerInformationEmpty(IResource resource) {
		final int PATH_ENTRY_MASK = IPathEntry.CDT_INCLUDE | IPathEntry.CDT_MACRO |
									IPathEntry.CDT_INCLUDE_FILE | IPathEntry.CDT_MACRO_FILE;
		boolean rc = true;
		IPath resPath = resource.getFullPath();
		IProject project = resource.getProject();

		ICProject cProject = CoreModel.getDefault().create(project);
		if (cProject != null) {
			try {
				IPathEntry[] resolvedPE = CoreModel.getRawPathEntries(cProject);
				for (IPathEntry pe : resolvedPE) {
					// first check all containers
					if (pe.getEntryKind() == IPathEntry.CDT_CONTAINER) {
						IPathEntryContainer peContainer = CoreModel.getPathEntryContainer(
								pe.getPath(), cProject);
						if (peContainer != null) {
							if (peContainer instanceof IPathEntryContainerExtension) {
								IPathEntryContainerExtension contExt = (IPathEntryContainerExtension) peContainer;
								if (!contExt.isEmpty(resPath)) {
									rc = false;
									break;
								}
							}
							else if (peContainer.getPathEntries().length > 0) {
								rc = false;
								break;
							}
						}
					}
					// then the user specified scanner info
					else if ((pe.getEntryKind() & PATH_ENTRY_MASK) != 0) {
						IPath affectedPath = pe.getPath();
						if (affectedPath.isPrefixOf(resource.getFullPath())) {
							rc = false;
							break;
						}
					}
				}
			} catch (CModelException e) {
			}
		}
		return rc;
	}

	/**
	 * This method is a full equivalent to {@code createProjectDescription(project, loadIfExists, false)}.
	 *
	 * @see #createProjectDescription(IProject, boolean, boolean)
	 */
	public ICProjectDescription createProjectDescription(IProject project, boolean loadIfExists) throws CoreException{
		return descriptionManager.createProjectDescription(project, loadIfExists);
	}

	/**
	 * Creates and returns a writable project description
	 *
	 * @param project project for which the project description is requested
	 * @param loadIfExists if true the method first tries to load and return the project description
	 * from the settings file (.cproject)
	 * if false, the stored settings are ignored and the new (empty) project description is created
	 * @param creating if true the created project description will be contain the true "isCdtProjectCreating" state.
	 * NOTE: in case the project already contains the project description AND its "isCdtProjectCreating" is false
	 * the resulting description will be created with the false "isCdtProjectCreating" state
	 *
	 * NOTE: changes made to the returned project description will not be applied until the {@link #setProjectDescription(IProject, ICProjectDescription)} is called
	 * @return {@link ICProjectDescription}
	 * @throws CoreException
	 */
	public ICProjectDescription createProjectDescription(IProject project, boolean loadIfExists, boolean creating) throws CoreException{
		return descriptionManager.createProjectDescription(project, loadIfExists, creating);
	}

	/**
	 * Returns the project description associated with this project or null if the project does not contain the
	 * CDT data associated with it.
	 *
	 * this is a convenience method fully equivalent to getProjectDescription(project, true)
	 * see {@link #getProjectDescription(IProject, boolean)} for more detail
	 * @param project
	 * @return a writable copy of the ICProjectDescription or null if the project does not contain the
	 * CDT data associated with it.
	 * Note: changes to the project description will not be reflected/used by the core
	 * until the {@link #setProjectDescription(IProject, ICProjectDescription)} is called
	 *
	 * @see #getProjectDescription(IProject, boolean)
	 */
	public ICProjectDescription getProjectDescription(IProject project){
		return descriptionManager.getProjectDescription(project);
	}

	/**
	 * This method is called to save/apply the project description
	 * the method should be called to apply changes made to the project description
	 * returned by the {@link #getProjectDescription(IProject, boolean)} or {@link #createProjectDescription(IProject, boolean)}
	 *
	 * @param project
	 * @param des
	 * @throws CoreException
	 *
	 * @see #getProjectDescription(IProject, boolean)
	 * @see #createProjectDescription(IProject, boolean)
	 */
	public void setProjectDescription(IProject project, ICProjectDescription des) throws CoreException {
		descriptionManager.setProjectDescription(project, des);
	}

	public void setProjectDescription(IProject project, ICProjectDescription des, boolean force, IProgressMonitor monitor) throws CoreException {
		descriptionManager.setProjectDescription(project, des, force, monitor);
	}

	/**
	 * returns the project description associated with this project or null if the project does not contain the
	 * CDT data associated with it.
	 *
	 * @param project project for which the description is requested
	 * @param write if true, the writable description copy is returned.
	 * If false the cached read-only description is returned.
	 *
	 * CDT core maintains the cached project description settings. If only read access is needed to description,
	 * then the read-only project description should be obtained.
	 * This description always operates with cached data and thus it is better to use it for performance reasons
	 * All set* calls to the read-only description result in the {@link WriteAccessException}
	 *
	 * When the writable description is requested, the description copy is created.
	 * Changes to this description will not be reflected/used by the core and Build System until the
	 * {@link #setProjectDescription(IProject, ICProjectDescription)} is called
	 *
	 * Each getProjectDescription(project, true) returns a new copy of the project description
	 *
	 * The writable description uses the cached data untill the first set call
	 * after that the description communicates directly to the Build System
	 * i.e. the implementer of the org.eclipse.cdt.core.CConfigurationDataProvider extension
	 * This ensures the Core<->Build System settings integrity
	 *
	 * @return {@link ICProjectDescription} or null if the project does not contain the
	 * CDT data associated with it.
	 */
	public ICProjectDescription getProjectDescription(IProject project, boolean write){
		return descriptionManager.getProjectDescription(project, write);
	}

	/**
	 * Forces the cached data of the specified projects to be re-calculated.
	 * If the {@code projects} argument is {@code null}, all projects
	 * within the workspace are updated.
	 *
	 * @param projects
	 * @param monitor
	 * @throws CoreException
	 */
	public void updateProjectDescriptions(IProject projects[], IProgressMonitor monitor) throws CoreException{
		descriptionManager.updateProjectDescriptions(projects, monitor);
	}

	/**
	 * Answers whether the given project is a new-style project,
	 * i.e. CConfigurationDataProvider-driven.
	 */
	public boolean isNewStyleProject(IProject project){
		return descriptionManager.isNewStyleProject(project);
	}

	/**
	 * Answers whether the given project is a new-style project,
	 * i.e. CConfigurationDataProvider-driven
	 */
	public boolean isNewStyleProject(ICProjectDescription des){
		return descriptionManager.isNewStyleProject(des);
	}

	public void addCProjectDescriptionListener(ICProjectDescriptionListener listener, int eventTypes){
		descriptionManager.addCProjectDescriptionListener(listener, eventTypes);
	}

	public void removeCProjectDescriptionListener(ICProjectDescriptionListener listener){
		descriptionManager.removeCProjectDescriptionListener(listener);
	}

	public ICProjectDescriptionManager getProjectDescriptionManager() {
		if (descriptionManager != null)
			return descriptionManager;
		
		// The method was called while initialization of the CoreModel hasn't finished yet. 
		return CProjectDescriptionManager.getInstance();
	}
}
